import sys
from pathlib import Path

from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
from PySide6.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PySide6.QtWidgets import (QApplication, QWidget, QLabel, QListWidgetItem)
from PySide6.QtGui import QPixmap, QColor, QFont, QBrush
from PySide6.QtCore import Qt, QTimer, QDateTime, QUrl

from interface.ui_autoInfo_vue_vin import Ui_Form
from utils.settingManager import setting_manager
from utils.redis_pubsub import RedisSubscribe


class AutoInfoVueWindow(QWidget, Ui_Form):
    def __init__(self, parent=None):
        super(AutoInfoVueWindow, self).__init__(parent)
        self.setupUi(self)
        self.timer = None  # 用于更新时间的线程
        self.media_player = None
        self.audio_output = None
        self.abnormal_list = []  # 用于判断异常列表展示什么
        self.initialization_ui()  # 初始化ui界面
        self.initialization_timer()  # 初始化定时器
        self.redis_subscribe_thread = None  # redis订阅线程
        self.initialization_pubsub_thread()  # 初始化redis线程，当窗口程序启动是就加载
        self.network_manager = QNetworkAccessManager()  # 初始化网络管理器
        self.initialization_media()  # 初始化媒体管理

    def initialization_ui(self):
        """初始化窗体"""
        # 1. 初始化工位代码的显示
        station_code = setting_manager.get_station_code()
        self.labelStationEidt.setText(str(station_code))
        # 2. 清空采集列表
        self.listWidgetCollectionList.clear()
        # 3. 清空当前采集的VIN号码
        self.labelCurrentVin.setText("")
        # 4. 采集过程中改成文字提示
        font = QFont()
        font.setPointSize(38)
        # 待采集
        self.labelCollectionStatus.setAlignment(Qt.AlignCenter)  # 居中显示
        self.labelCollectionStatus.setFont(font)
        self.labelCollectionStatus.setText('<span style="color: #1d953f;">等待采集</span>')
        # 待上传
        self.labelUpoladStatus.setAlignment(Qt.AlignCenter)
        self.labelUpoladStatus.setFont(font)
        self.labelUpoladStatus.setText('<span style="color: #1d953f;">空闲中</span>')
        # OCR识别
        self.labelOCRStatus.setAlignment(Qt.AlignCenter)
        self.labelOCRStatus.setFont(font)
        self.labelOCRStatus.setText('<span style="color: #1d953f;">等待采集</span>')
        if not self.abnormal_list:
            self.listWidgetAbnormalList.hide()
        # 初始化log
        pixmap = QPixmap("interface/images/faw_log.png")
        self.pixmap_label_show(pixmap, self.labelLogo)

    def initialization_timer(self):
        """常用应用的初始化"""
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_datetime)
        self.timer.start(1000)  # 每秒更新一次

    def initialization_pubsub_thread(self):
        """初始化订阅线程"""
        self.redis_subscribe_thread = RedisSubscribe()
        self.redis_subscribe_thread.signal.connect(self.refresh_interface)  # 获取线程订阅数据
        self.redis_subscribe_thread.start()  # 启动线程

    def update_datetime(self):
        """获取当前时间"""
        current_datetime = QDateTime.currentDateTime()
        # 更新日期
        self.labelCurrentDate.setText(current_datetime.toString("yyyy-MM-dd"))
        # 更新星期（转换为中文）
        week_day_map = {
            "Monday": "星期一",
            "Tuesday": "星期二",
            "Wednesday": "星期三",
            "Thursday": "星期四",
            "Friday": "星期五",
            "Saturday": "星期六",
            "Sunday": "星期日"
        }
        english_week = current_datetime.toString("dddd")
        chinese_week = week_day_map.get(english_week, english_week)  # 默认返回原英文以防万一
        self.labelCurrentWeek.setText(chinese_week)
        # 更新时间
        self.labelCurrentTime.setText(current_datetime.toString("hh:mm:ss"))

    def refresh_interface(self, message: dict):
        """刷新界面数据，
        :param message: 订阅线程执行得到订阅消息"""
        if not message or not isinstance(message, dict):  # 消息要存在且必须是字典格式
            return
        process = message.get('process')
        process_dict = {'start': self.start_detection, 'end': self.end_detection, 'upload': self.upload_detection}
        if callable(process_dict.get(process)):
            process_dict.get(process)(message)

    def start_detection(self, message: dict):
        """检测开始的显示
        :param message: 需要在界面上刷新的数据
        """
        # 1. 刷新当前采集的VIN
        font = self.labelCurrentVin.font()
        font.setPointSize(48)  # 设置字体大小为48
        vin = message.get('current_vin')  # 当前扫码的VIN号码
        self.labelCurrentVin.setText(vin)
        self.labelCurrentVin.setFont(font)
        self.labelCurrentVin.setText(vin)
        # 3. 清空vin1:1照片
        self.labelCollectedVin.clear()
        # 2. 清空采集过程进度
        clear_list = [self.labelCollectionStatus, self.labelOCRStatus, self.labelUpoladStatus]  # 采集、OCR、上传
        [widget.clear() for widget in clear_list]  # 执行清空操作

    def end_detection(self, message: dict):
        """检测结束的显示
        :param message: 需要在界面上刷新的数据"""
        # 1. 获取需要刷新的相关数据
        vin_jpg_path_url = message.get('jpg_path', '')  # 1:1vin采集图片
        captured_count = message.get('captured_count', 0)  # 已经采集的数量
        abnormal_count = message.get('abnormal_count', 0)  # 异常采集的数量
        missed_count = message.get('missed_count', 0)  # 漏采数量
        state = message.get('state', 'failure')  # 1：1复原的状态，failure表示失败， success表示成功
        captured_list = message.get('captured_list', [])  # 采集列表
        abnormal_list = message.get('abnormal_list', [])  # 异常列表
        missed_list = message.get('missed_list', [])  # 漏采列表
        ocr_vin_result_dict = message.get('ocr_vin_result', {})  # OCR识别的结果返回是一个字典
        ocr_vin_judge = ocr_vin_result_dict.get('ocr_vin_judge', '')  # "1" 表示一致， 其他表示不一致
        # 3. 刷新VIN采集的照片
        if not vin_jpg_path_url:
            self.labelCollectedVin.setText("未获取到图片路径")
        else:
            self.load_network_image(vin_jpg_path_url)
        # 4. 刷新已采集列表
        self.refresh_capture_data(captured_count, captured_list)
        # 5. 更新采集图标（根据成功和失败来进行判定）
        self.refresh_capture_result(state)
        # 6. 更新OCR识别
        self.refresh_ocr_result(ocr_vin_judge, state)
        # 刷新异常数量和列表
        self.refresh_abnormal_data(abnormal_count, missed_count, abnormal_list, missed_list)
        self.play_failure_music(state)

    def play_failure_music(self, state: str):
        """采集失败，播放失败音乐
        :param state: 采集的状态"""
        if state == 'failure':
            self.play_music()

    def refresh_capture_data(self, captured_count: int, captured_list: list):
        """刷新已采集列表
        :param captured_count: 已采集数量
        :param captured_list: 已采集列表"""
        self.labelCurrentCountText.setText(str(captured_count))
        self.listWidgetCollectionList.clear()  # 先清空原来的数据
        font = QFont()
        font.setPointSize(28)  # 设置字体大小
        font.setBold(True)  # 是否加粗
        text_brush = QBrush(QColor('#6f6d85'))  # 设置为灰色
        highlight_brush = QBrush(QColor('#00a6ac'))  # 选中项的颜色，这里用红色示例
        for index, captured_item in enumerate(captured_list):
            item = QListWidgetItem(str(captured_item))
            item.setFont(font)  # 设置字体
            if index == 0:
                item.setForeground(highlight_brush)  # 是首行的时候给他另外一个颜色
            else:
                item.setForeground(text_brush)  # 设置字体颜色
            self.listWidgetCollectionList.addItem(item)
        # 设置第一行为选中状态
        if captured_list:  # 确保列表不为空
            self.listWidgetCollectionList.setCurrentRow(0)

    def upload_detection(self, message: dict):
        """上传完成界面显示
        :param message: 需要在界面上刷新的数据
        """
        status = message.get('status', 'failure')
        if status == 'failure':
            pixmap = QPixmap("interface/images/upload_failure.png")
            self.pixmap_label_show(pixmap, self.labelUpoladStatus)
        elif status == 'success':
            pixmap = QPixmap("interface/images/upload_success.png")
            self.pixmap_label_show(pixmap, self.labelUpoladStatus)

    def refresh_capture_result(self, state: str):
        """刷新采集结果
        :param state:采集状态"""
        if state == 'failure':
            pixmap = QPixmap("interface/images/collection_failure.png")
            self.pixmap_label_show(pixmap, self.labelCollectionStatus)
        elif state == 'success':
            pixmap = QPixmap("interface/images/collection_success.png")
            self.pixmap_label_show(pixmap, self.labelCollectionStatus)
        else:
            pixmap = QPixmap("interface/images/collection_failure.png")
            self.pixmap_label_show(pixmap, self.labelCollectionStatus)

    def refresh_ocr_result(self, ocr_vin_judge: str, state: str):
        """刷新界面OCR识别判定结果
        :param ocr_vin_judge: OCR的识别结果
        :param state: 采集状态，如果采集就失败了，无法完成OCR识别的,必然是失败
        """
        if state == 'failure':
            pixmap = QPixmap("interface/images/ocr_failure.png")
            self.pixmap_label_show(pixmap, self.labelOCRStatus)
        if ocr_vin_judge == '1':
            pixmap = QPixmap("interface/images/ocr_success.png")
            self.pixmap_label_show(pixmap, self.labelOCRStatus)
        else:
            pixmap = QPixmap("interface/images/ocr_failure.png")
            self.pixmap_label_show(pixmap, self.labelOCRStatus)

    def refresh_abnormal_data(self, abnormal_count: int, missed_count: int, abnormal_list: list, missed_list: list):
        """刷新界面异常数量与列表
        :param abnormal_count: 采集异常的数量
        :param missed_count: 漏采数量
        :param abnormal_list: 异常列表
        :param missed_list 漏采列表"""
        new_abnormal_count = abnormal_count + missed_count  # 异常数量等于异常数量+漏采数量
        new_abnormal_list = abnormal_list + missed_list  # 异常列表等于异常列表+漏采列表
        self.labelAbnormalCount.setText(str(new_abnormal_count))
        if not new_abnormal_list:  # 没有数据，这里就显示无报警的图片提示
            return
        self.listWidgetAbnormalList.show()  # 显示列表
        self.labelNoAbnormal.hide()  # 隐藏报警图片
        self.listWidgetAbnormalList.clear()  # 清空原来的列表
        font = QFont()
        font.setPointSize(28)
        font.setBold(True)
        text_brush = QBrush(QColor('#f26522'))
        for abnormal_item in abnormal_list:
            item = QListWidgetItem(str(abnormal_item))
            item.setFont(font)
            item.setForeground(text_brush)
            self.listWidgetAbnormalList.addItem(item)

    def pixmap_label_show(self, pixmap: QPixmap, label: QLabel):
        """自定义图片在label标签中居中展示
        :param pixmap: 需要显示的图片
        :param label: 控件，暂时支持label控件"""
        scaled_pixmap = pixmap.scaled(label.size(),
                                      Qt.KeepAspectRatio,
                                      Qt.SmoothTransformation)
        label.setPixmap(scaled_pixmap)
        label.setAlignment(Qt.AlignCenter)

    def load_network_image(self, url_str: str):
        """异步加载网络图片并显示"""
        url = QUrl(url_str)
        if not url.isValid():
            self.labelCollectedVin.setText('无效的URL')
            return
        request = QNetworkRequest(url)
        reply = self.network_manager.get(request)

        # 异步处理网络请求结果
        def handle_finished():
            image_data = reply.readAll()
            pixmap = QPixmap()
            if pixmap.loadFromData(image_data):
                # 缩放图片以适应Label（保持比例）
                self.pixmap_label_show(pixmap, self.labelCollectedVin)
                # self.labelCollectedVin.setText('')  # 清除文本
            reply.deleteLater()

        reply.finished.connect(handle_finished)

    def play_music(self):
        """播放音乐"""
        music_path = Path('music') / '采集失败音效.mp3'
        if not music_path.exists():
            return
        media_content = QUrl.fromLocalFile(music_path)
        self.media_player.setSource(media_content)
        self.media_player.play()

    def initialization_media(self):
        """初始化媒体文件"""
        self.media_player = QMediaPlayer()
        self.audio_output = QAudioOutput()
        self.media_player.setAudioOutput(self.audio_output)
        self.audio_output.setVolume(0.5)

    def closeEvent(self, event):
        """重写关闭事件以终止Redis订阅线程"""
        if self.redis_subscribe_thread:
            self.redis_subscribe_thread.is_running = False  # 需在RedisSubscribe类中添加此标志
            self.redis_subscribe_thread.wait()  # 等待线程结束
        super().closeEvent(event)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ui = AutoInfoVueWindow()
    ui.show()
    app.exec()
